package com.klikmee.sms.core.base.communicator.telenor;

import java.net.URL;
import java.util.List;
import java.util.Map;

import javax.xml.namespace.QName;
import javax.xml.ws.BindingProvider;

import org.apache.log4j.Logger;

import com.klikmee.sms.core.base.dao.ConfigDAO;
import com.klikmee.sms.core.base.dao.ConfigFacadeLocal;
import com.klikmee.sms.core.base.util.Constants;
import com.klikmee.sms.core.ws.telenor.client.receivesms.GetReceivedSmsByCpseq;
import com.klikmee.sms.core.ws.telenor.client.receivesms.GetReceivedSmsByCpseqResponse;
import com.klikmee.sms.core.ws.telenor.client.receivesms.GetReceivedSmsExt;
import com.klikmee.sms.core.ws.telenor.client.receivesms.GetReceivedSmsExtResponse;
import com.klikmee.sms.core.ws.telenor.client.receivesms.Potpis;
import com.klikmee.sms.core.ws.telenor.client.receivesms.SmsParlayx;
import com.klikmee.sms.core.ws.telenor.client.receivesms.SmsTypeExt;

/**
 * 
 * @author makcro
 *         <p>
 *         this class is used to check for any incoming messages sent from
 *         mobile phone via telenor operater. it's execution is scheduled in
 *         telenor communicator, using java.util.Timer.
 *         </p>
 *         <p>
 *         messages are retrieved via ws client (method getReceivedSmsExt()). in
 *         case of communication failure there is a helper method,
 *         getReceivedByCpseq().
 *         </p>
 *         <p>
 *         Every 'get messages' request has its id, which is created by
 *         TelenorCommunicator. Id is generated by system.currentTimeInMill().
 *         Before every request cpseq is saved in database. If request was
 *         successful, cpseq is deleted from database. If exception is thrown
 *         during getReceivedSmsExt() call, cpseq is not deleted. On every
 *         invocation of run() method, program checks for existence of cpseq in
 *         database and if it exists then request for message retrieval is made
 *         with that cpseq stored in database. After successful ws clients
 *         getReceivedSmsByCpseq call, this cpseq is deleted, so that next
 *         invocation goes normal.
 *         </p>
 * 
 */
public class GetMessagesFromCPA {

    private ConfigDAO configDAO;
    public static Logger logger = Logger.getLogger( GetMessagesFromCPA.class );
    // interface to telenor cpa
    private com.klikmee.sms.core.ws.telenor.client.receivesms.SmsParlayx receiveSMSServiceEndpoint = null;
    private URL wsdlURL;
    private String overrideEndpointAddress;
    private TelenorCommunicatorImpl communicator = null;
    private String cpId = null;
    private com.klikmee.sms.core.ws.telenor.client.receivesms.Potpis credentials = null;

    public GetMessagesFromCPA() {
    }

    public void init() {
        
        receiveSMSServiceEndpoint = new com.klikmee.sms.core.ws.telenor.client.receivesms.SmsParlayxService( wsdlURL, new QName( "http://telenor.cpa.parlayx.sms", "SmsParlayxService" ) ).getSmsParlayxPort();
        if(overrideEndpointAddress != null){
            BindingProvider sendsmsBP = (BindingProvider) receiveSMSServiceEndpoint;
            Map<String, Object> sendsmsRequestContext = sendsmsBP.getRequestContext();
            sendsmsRequestContext.put( BindingProvider.ENDPOINT_ADDRESS_PROPERTY, overrideEndpointAddress );
        }
    }

    public void checkForMessages() {


        // this will be delivered to telenor communicator
        List<SmsTypeExt> messages = null;

        // first check for cpseq in database which indicates that previous
        // message
        // request failed
        String cpseq = configDAO.getParameterValue( Constants.CONF_TELENOR_RECEIVE_SMS_CPSEQ_VALUE );

        // if everything is okay, then proceed normally
        if (cpseq == null) {

            // create cpseq for this request
            long currentCpseq = System.currentTimeMillis();

            // set request parameters
            GetReceivedSmsExt getReceivedSmsExtParameters = new GetReceivedSmsExt();
            getReceivedSmsExtParameters.setCpseqid( currentCpseq );
            getReceivedSmsExtParameters.setRegistrationIdentifier( Long.parseLong( cpId ) );

            // save cpseq before request
            configDAO.createParameter(
                    Constants.CONF_TELENOR_RECEIVE_SMS_CPSEQ_VALUE,
                    String.valueOf( currentCpseq ) );

            try {
                GetReceivedSmsExtResponse payload = receiveSMSServiceEndpoint.getReceivedSmsExt(
                        getReceivedSmsExtParameters,
                        credentials );

                messages = payload.getReturn();
                // everything ok, delete cpseq
                configDAO.deleteParameter( Constants.CONF_TELENOR_RECEIVE_SMS_CPSEQ_VALUE );

            } catch (Exception e) {
                // if there is an error, save cpseq so that next invocation
                // corrects error
                // writeFile(cpseq);
                logger.fatal( "Error getting messages using getReceivedSmsByExt.. cpseq = " + cpseq, e );
            }

        } // if cpseq is found then retry request
        else {
            logger.info( "found cpsql = " + cpseq + " retrying to get messages..." );
            long cpSeqLong = Long.parseLong( cpseq );

            try {
                GetReceivedSmsByCpseq byCpseq = new GetReceivedSmsByCpseq();
                byCpseq.setCpseqid( cpSeqLong );
                byCpseq.setRegistrationIdentifier( Long.parseLong( cpId ) );

                GetReceivedSmsByCpseqResponse payload = receiveSMSServiceEndpoint.getReceivedSmsByCpseq(
                        byCpseq,
                        credentials );
                messages = payload.getReturn();

                // if every thing is ok then delete row from db
                configDAO.deleteParameter( Constants.CONF_TELENOR_RECEIVE_SMS_CPSEQ_VALUE );

            } catch (Exception e) {
                logger.fatal( "Retrying to get messages faild with cpseq = " + cpseq, e );
            }

        }

        // only if messages are retreived make call to telenor communicator
        if (messages != null) {
            logger.debug( "Pickup " + messages.size() + " message(s) from Telenor CPA, forwarding to Core..." );
            communicator.onMessagesReceived( messages );

        }

    }

    public void setCommunicator( TelenorCommunicatorImpl communicator ) {
        this.communicator = communicator;
    }

    public void setConfigDAO( ConfigDAO configDAO ) {
        this.configDAO = configDAO;
    }

    public void setCpId( String cpId ) {
        this.cpId = cpId;
    }

    public void setCredentials( Potpis credentials ) {
        this.credentials = credentials;
    }

    public void setReceiveSMSServiceEndpoint( SmsParlayx receiveSMSServiceEndpoint ) {
        this.receiveSMSServiceEndpoint = receiveSMSServiceEndpoint;
    }

    public void setWsdlURL( URL wsdlURL ) {
        this.wsdlURL = wsdlURL;
    }
    
    public void setOverrideEndpointAddress( String overrideEndpointAddress ) {
		this.overrideEndpointAddress = overrideEndpointAddress;
	}

}
